package com.datagateway.component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 服务发现管理器
 * 负责服务注册、发现和健康检查，支持动态服务管理
 * 
 * @author Data Gateway Team
 * @version 1.0.0
 */
@Component
public class ServiceDiscoveryManager {

    private static final Logger logger = LoggerFactory.getLogger(ServiceDiscoveryManager.class);

    @Autowired
    private LoadBalancerManager loadBalancerManager;

    @Autowired
    private AlertManager alertManager;

    @Autowired
    private SystemMonitor systemMonitor;

    /**
     * 服务发现统计信息
     */
    private final AtomicLong totalRegistrations = new AtomicLong(0);
    private final AtomicLong totalDeregistrations = new AtomicLong(0);
    private final AtomicLong totalDiscoveries = new AtomicLong(0);
    private final AtomicLong totalHealthChecks = new AtomicLong(0);

    /**
     * 服务发现配置
     */
    private boolean serviceDiscoveryEnabled = true;
    private int serviceRegistrationTimeoutSeconds = 30;
    private int serviceHeartbeatIntervalSeconds = 10;
    private int serviceExpirationTimeSeconds = 60;
    private int discoveryCacheTimeoutSeconds = 30;

    /**
     * 服务注册表
     */
    private final Map<String, ServiceInfo> serviceRegistry = new ConcurrentHashMap<>();
    private final Map<String, Set<String>> serviceGroups = new ConcurrentHashMap<>();
    private final Map<String, ServiceHealth> serviceHealthMap = new ConcurrentHashMap<>();

    /**
     * 服务发现缓存
     */
    private final Map<String, List<ServiceInfo>> discoveryCache = new ConcurrentHashMap<>();
    private final Map<String, Long> cacheTimestamps = new ConcurrentHashMap<>();

    /**
     * 执行器
     */
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3, r -> {
        Thread t = new Thread(r, "service-discovery-scheduler");
        t.setDaemon(true);
        return t;
    });

    /**
     * 初始化服务发现管理器
     */
    public void initialize() {
        try {
            // 启动服务清理任务
            startServiceCleanupTask();
            
            // 启动服务健康检查任务
            startServiceHealthCheckTask();
            
            // 启动缓存清理任务
            startCacheCleanupTask();
            
            logger.info("服务发现管理器初始化成功");
            
        } catch (Exception e) {
            logger.error("服务发现管理器初始化失败", e);
            alertManager.sendSystemErrorAlert("服务发现管理器初始化失败", e.getMessage());
        }
    }

    /**
     * 停止服务发现管理器
     */
    public void stop() {
        try {
            scheduler.shutdown();
            if (!scheduler.awaitTermination(30, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
            }
            
            logger.info("服务发现管理器停止成功");
            
        } catch (Exception e) {
            logger.error("服务发现管理器停止失败", e);
        }
    }

    /**
     * 注册服务
     * 
     * @param serviceInfo 服务信息
     * @return 是否注册成功
     */
    public boolean registerService(ServiceInfo serviceInfo) {
        if (!serviceDiscoveryEnabled) {
            logger.debug("服务发现已禁用，跳过服务注册: {}", serviceInfo.getServiceId());
            return false;
        }

        try {
            serviceInfo.setRegistrationTime(System.currentTimeMillis());
            serviceInfo.setLastHeartbeat(System.currentTimeMillis());
            serviceInfo.setStatus(ServiceStatus.ACTIVE);
            
            serviceRegistry.put(serviceInfo.getServiceId(), serviceInfo);
            
            // 添加到服务组
            addToServiceGroup(serviceInfo);
            
            // 添加到负载均衡器
            loadBalancerManager.addServiceInstance(
                serviceInfo.getServiceId(),
                serviceInfo.getHost(),
                serviceInfo.getPort(),
                serviceInfo.getWeight()
            );
            
            // 初始化健康状态
            serviceHealthMap.put(serviceInfo.getServiceId(), new ServiceHealth(
                serviceInfo.getServiceId(),
                HealthStatus.HEALTHY,
                System.currentTimeMillis()
            ));
            
            totalRegistrations.incrementAndGet();
            
            logger.info("服务注册成功: {} -> {}:{}", 
                       serviceInfo.getServiceId(), serviceInfo.getHost(), serviceInfo.getPort());
            
            return true;
            
        } catch (Exception e) {
            logger.error("服务注册失败: {}", serviceInfo.getServiceId(), e);
            alertManager.sendSystemErrorAlert("服务注册失败", e.getMessage());
            return false;
        }
    }

    /**
     * 注销服务
     * 
     * @param serviceId 服务ID
     * @return 是否注销成功
     */
    public boolean deregisterService(String serviceId) {
        try {
            ServiceInfo serviceInfo = serviceRegistry.remove(serviceId);
            if (serviceInfo != null) {
                // 从服务组中移除
                removeFromServiceGroup(serviceInfo);
                
                // 从负载均衡器中移除
                loadBalancerManager.removeServiceInstance(serviceId);
                
                // 移除健康状态
                serviceHealthMap.remove(serviceId);
                
                // 清除缓存
                clearDiscoveryCache(serviceInfo.getServiceName());
                
                totalDeregistrations.incrementAndGet();
                
                logger.info("服务注销成功: {}", serviceId);
                return true;
            }
            
            return false;
            
        } catch (Exception e) {
            logger.error("服务注销失败: {}", serviceId, e);
            return false;
        }
    }

    /**
     * 发现服务
     * 
     * @param serviceName 服务名称
     * @return 服务列表
     */
    public List<ServiceInfo> discoverServices(String serviceName) {
        if (!serviceDiscoveryEnabled) {
            logger.debug("服务发现已禁用，跳过服务发现: {}", serviceName);
            return new ArrayList<>();
        }

        try {
            totalDiscoveries.incrementAndGet();
            
            // 检查缓存
            List<ServiceInfo> cachedServices = getCachedServices(serviceName);
            if (cachedServices != null) {
                return cachedServices;
            }
            
            // 从注册表查找服务
            List<ServiceInfo> services = new ArrayList<>();
            for (ServiceInfo serviceInfo : serviceRegistry.values()) {
                if (serviceName.equals(serviceInfo.getServiceName()) && 
                    serviceInfo.getStatus() == ServiceStatus.ACTIVE) {
                    services.add(serviceInfo);
                }
            }
            
            // 缓存结果
            cacheServices(serviceName, services);
            
            logger.debug("服务发现完成: {} -> {} 个实例", serviceName, services.size());
            
            return services;
            
        } catch (Exception e) {
            logger.error("服务发现失败: {}", serviceName, e);
            return new ArrayList<>();
        }
    }

    /**
     * 发送心跳
     * 
     * @param serviceId 服务ID
     * @return 是否成功
     */
    public boolean sendHeartbeat(String serviceId) {
        try {
            ServiceInfo serviceInfo = serviceRegistry.get(serviceId);
            if (serviceInfo != null) {
                serviceInfo.setLastHeartbeat(System.currentTimeMillis());
                serviceInfo.setStatus(ServiceStatus.ACTIVE);
                
                // 更新健康状态
                ServiceHealth health = serviceHealthMap.get(serviceId);
                if (health != null) {
                    health.setLastCheckTime(System.currentTimeMillis());
                    health.setStatus(HealthStatus.HEALTHY);
                }
                
                logger.debug("心跳更新成功: {}", serviceId);
                return true;
            }
            
            return false;
            
        } catch (Exception e) {
            logger.error("发送心跳失败: {}", serviceId, e);
            return false;
        }
    }

    /**
     * 获取服务信息
     * 
     * @param serviceId 服务ID
     * @return 服务信息
     */
    public ServiceInfo getServiceInfo(String serviceId) {
        return serviceRegistry.get(serviceId);
    }

    /**
     * 获取所有服务信息
     * 
     * @return 服务信息列表
     */
    public List<ServiceInfo> getAllServices() {
        return new ArrayList<>(serviceRegistry.values());
    }

    /**
     * 获取服务组信息
     * 
     * @param serviceName 服务名称
     * @return 服务组信息
     */
    public ServiceGroup getServiceGroup(String serviceName) {
        Set<String> serviceIds = serviceGroups.get(serviceName);
        if (serviceIds == null || serviceIds.isEmpty()) {
            return new ServiceGroup(serviceName, new ArrayList<>());
        }
        
        List<ServiceInfo> services = new ArrayList<>();
        for (String serviceId : serviceIds) {
            ServiceInfo serviceInfo = serviceRegistry.get(serviceId);
            if (serviceInfo != null) {
                services.add(serviceInfo);
            }
        }
        
        return new ServiceGroup(serviceName, services);
    }

    /**
     * 获取服务健康状态
     * 
     * @param serviceId 服务ID
     * @return 健康状态
     */
    public ServiceHealth getServiceHealth(String serviceId) {
        return serviceHealthMap.get(serviceId);
    }

    /**
     * 获取所有服务健康状态
     * 
     * @return 健康状态列表
     */
    public List<ServiceHealth> getAllServiceHealth() {
        return new ArrayList<>(serviceHealthMap.values());
    }

    /**
     * 获取服务发现统计信息
     * 
     * @return 统计信息
     */
    public ServiceDiscoveryStatistics getStatistics() {
        return new ServiceDiscoveryStatistics(
            totalRegistrations.get(),
            totalDeregistrations.get(),
            totalDiscoveries.get(),
            totalHealthChecks.get(),
            serviceRegistry.size(),
            serviceGroups.size(),
            serviceDiscoveryEnabled,
            serviceRegistrationTimeoutSeconds,
            serviceHeartbeatIntervalSeconds,
            serviceExpirationTimeSeconds,
            System.currentTimeMillis()
        );
    }

    /**
     * 设置服务发现配置
     * 
     * @param enabled 是否启用服务发现
     * @param registrationTimeout 注册超时时间
     * @param heartbeatInterval 心跳间隔
     * @param expirationTime 过期时间
     * @param cacheTimeout 缓存超时时间
     */
    public void setServiceDiscoveryConfig(boolean enabled, int registrationTimeout, 
                                        int heartbeatInterval, int expirationTime, int cacheTimeout) {
        this.serviceDiscoveryEnabled = enabled;
        this.serviceRegistrationTimeoutSeconds = registrationTimeout;
        this.serviceHeartbeatIntervalSeconds = heartbeatInterval;
        this.serviceExpirationTimeSeconds = expirationTime;
        this.discoveryCacheTimeoutSeconds = cacheTimeout;
        
        logger.info("服务发现配置已更新: 启用={}, 注册超时={}, 心跳间隔={}, 过期时间={}, 缓存超时={}", 
                   enabled, registrationTimeout, heartbeatInterval, expirationTime, cacheTimeout);
    }

    /**
     * 添加到服务组
     * 
     * @param serviceInfo 服务信息
     */
    private void addToServiceGroup(ServiceInfo serviceInfo) {
        String serviceName = serviceInfo.getServiceName();
        serviceGroups.computeIfAbsent(serviceName, k -> new HashSet<>()).add(serviceInfo.getServiceId());
    }

    /**
     * 从服务组中移除
     * 
     * @param serviceInfo 服务信息
     */
    private void removeFromServiceGroup(ServiceInfo serviceInfo) {
        String serviceName = serviceInfo.getServiceName();
        Set<String> serviceIds = serviceGroups.get(serviceName);
        if (serviceIds != null) {
            serviceIds.remove(serviceInfo.getServiceId());
            if (serviceIds.isEmpty()) {
                serviceGroups.remove(serviceName);
            }
        }
    }

    /**
     * 获取缓存的服务
     * 
     * @param serviceName 服务名称
     * @return 缓存的服务列表
     */
    private List<ServiceInfo> getCachedServices(String serviceName) {
        Long cacheTime = cacheTimestamps.get(serviceName);
        if (cacheTime != null && 
            System.currentTimeMillis() - cacheTime < discoveryCacheTimeoutSeconds * 1000) {
            return discoveryCache.get(serviceName);
        }
        return null;
    }

    /**
     * 缓存服务
     * 
     * @param serviceName 服务名称
     * @param services 服务列表
     */
    private void cacheServices(String serviceName, List<ServiceInfo> services) {
        discoveryCache.put(serviceName, new ArrayList<>(services));
        cacheTimestamps.put(serviceName, System.currentTimeMillis());
    }

    /**
     * 清除发现缓存
     * 
     * @param serviceName 服务名称
     */
    private void clearDiscoveryCache(String serviceName) {
        discoveryCache.remove(serviceName);
        cacheTimestamps.remove(serviceName);
    }

    /**
     * 启动服务清理任务
     */
    private void startServiceCleanupTask() {
        scheduler.scheduleAtFixedRate(this::cleanupExpiredServices, 
            60, 30, TimeUnit.SECONDS);
    }

    /**
     * 启动服务健康检查任务
     */
    private void startServiceHealthCheckTask() {
        scheduler.scheduleAtFixedRate(this::performHealthCheck, 
            0, serviceHeartbeatIntervalSeconds, TimeUnit.SECONDS);
    }

    /**
     * 启动缓存清理任务
     */
    private void startCacheCleanupTask() {
        scheduler.scheduleAtFixedRate(this::cleanupExpiredCache, 
            0, 60, TimeUnit.SECONDS);
    }

    /**
     * 清理过期服务
     */
    private void cleanupExpiredServices() {
        try {
            long currentTime = System.currentTimeMillis();
            long expirationTime = serviceExpirationTimeSeconds * 1000;
            
            List<String> expiredServices = new ArrayList<>();
            for (ServiceInfo serviceInfo : serviceRegistry.values()) {
                if (currentTime - serviceInfo.getLastHeartbeat() > expirationTime) {
                    expiredServices.add(serviceInfo.getServiceId());
                }
            }
            
            for (String serviceId : expiredServices) {
                deregisterService(serviceId);
                logger.info("清理过期服务: {}", serviceId);
            }
            
        } catch (Exception e) {
            logger.error("清理过期服务失败", e);
        }
    }

    /**
     * 执行健康检查
     */
    private void performHealthCheck() {
        try {
            totalHealthChecks.incrementAndGet();
            
            for (ServiceInfo serviceInfo : serviceRegistry.values()) {
                boolean isHealthy = checkServiceHealth(serviceInfo);
                
                ServiceHealth health = serviceHealthMap.get(serviceInfo.getServiceId());
                if (health != null) {
                    health.setStatus(isHealthy ? HealthStatus.HEALTHY : HealthStatus.UNHEALTHY);
                    health.setLastCheckTime(System.currentTimeMillis());
                }
            }
            
        } catch (Exception e) {
            logger.error("执行健康检查失败", e);
        }
    }

    /**
     * 清理过期缓存
     */
    private void cleanupExpiredCache() {
        try {
            long currentTime = System.currentTimeMillis();
            long cacheTimeout = discoveryCacheTimeoutSeconds * 1000;
            
            List<String> expiredKeys = new ArrayList<>();
            for (Map.Entry<String, Long> entry : cacheTimestamps.entrySet()) {
                if (currentTime - entry.getValue() > cacheTimeout) {
                    expiredKeys.add(entry.getKey());
                }
            }
            
            for (String key : expiredKeys) {
                discoveryCache.remove(key);
                cacheTimestamps.remove(key);
            }
            
        } catch (Exception e) {
            logger.error("清理过期缓存失败", e);
        }
    }

    /**
     * 检查服务健康状态
     * 
     * @param serviceInfo 服务信息
     * @return 是否健康
     */
    private boolean checkServiceHealth(ServiceInfo serviceInfo) {
        try {
            // 这里可以实现具体的健康检查逻辑
            // 例如：发送HTTP请求到健康检查端点
            // 简化实现：检查心跳时间
            long currentTime = System.currentTimeMillis();
            long heartbeatTimeout = serviceHeartbeatIntervalSeconds * 3 * 1000; // 3倍心跳间隔
            
            return currentTime - serviceInfo.getLastHeartbeat() < heartbeatTimeout;
            
        } catch (Exception e) {
            logger.error("检查服务健康状态失败: {}", serviceInfo.getServiceId(), e);
            return false;
        }
    }

    /**
     * 服务信息类
     */
    public static class ServiceInfo {
        private String serviceId;
        private String serviceName;
        private String host;
        private int port;
        private int weight;
        private ServiceStatus status;
        private long registrationTime;
        private long lastHeartbeat;
        private Map<String, String> metadata;

        public ServiceInfo(String serviceId, String serviceName, String host, int port, int weight) {
            this.serviceId = serviceId;
            this.serviceName = serviceName;
            this.host = host;
            this.port = port;
            this.weight = weight;
            this.metadata = new HashMap<>();
        }

        // Getter和Setter方法
        public String getServiceId() { return serviceId; }
        public void setServiceId(String serviceId) { this.serviceId = serviceId; }
        public String getServiceName() { return serviceName; }
        public void setServiceName(String serviceName) { this.serviceName = serviceName; }
        public String getHost() { return host; }
        public void setHost(String host) { this.host = host; }
        public int getPort() { return port; }
        public void setPort(int port) { this.port = port; }
        public int getWeight() { return weight; }
        public void setWeight(int weight) { this.weight = weight; }
        public ServiceStatus getStatus() { return status; }
        public void setStatus(ServiceStatus status) { this.status = status; }
        public long getRegistrationTime() { return registrationTime; }
        public void setRegistrationTime(long registrationTime) { this.registrationTime = registrationTime; }
        public long getLastHeartbeat() { return lastHeartbeat; }
        public void setLastHeartbeat(long lastHeartbeat) { this.lastHeartbeat = lastHeartbeat; }
        public Map<String, String> getMetadata() { return metadata; }
        public void setMetadata(Map<String, String> metadata) { this.metadata = metadata; }
    }

    /**
     * 服务状态枚举
     */
    public enum ServiceStatus {
        ACTIVE,     // 活跃
        INACTIVE,   // 非活跃
        MAINTENANCE // 维护中
    }

    /**
     * 健康状态枚举
     */
    public enum HealthStatus {
        HEALTHY,    // 健康
        UNHEALTHY,  // 不健康
        UNKNOWN     // 未知
    }

    /**
     * 服务健康类
     */
    public static class ServiceHealth {
        private String serviceId;
        private HealthStatus status;
        private long lastCheckTime;
        private String message;

        public ServiceHealth(String serviceId, HealthStatus status, long lastCheckTime) {
            this.serviceId = serviceId;
            this.status = status;
            this.lastCheckTime = lastCheckTime;
        }

        // Getter和Setter方法
        public String getServiceId() { return serviceId; }
        public void setServiceId(String serviceId) { this.serviceId = serviceId; }
        public HealthStatus getStatus() { return status; }
        public void setStatus(HealthStatus status) { this.status = status; }
        public long getLastCheckTime() { return lastCheckTime; }
        public void setLastCheckTime(long lastCheckTime) { this.lastCheckTime = lastCheckTime; }
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
    }

    /**
     * 服务组类
     */
    public static class ServiceGroup {
        private String serviceName;
        private List<ServiceInfo> services;

        public ServiceGroup(String serviceName, List<ServiceInfo> services) {
            this.serviceName = serviceName;
            this.services = services;
        }

        // Getter方法
        public String getServiceName() { return serviceName; }
        public List<ServiceInfo> getServices() { return services; }
        public int getServiceCount() { return services.size(); }
    }

    /**
     * 服务发现统计信息类
     */
    public static class ServiceDiscoveryStatistics {
        private final long totalRegistrations;
        private final long totalDeregistrations;
        private final long totalDiscoveries;
        private final long totalHealthChecks;
        private final int registeredServices;
        private final int serviceGroups;
        private final boolean serviceDiscoveryEnabled;
        private final int registrationTimeout;
        private final int heartbeatInterval;
        private final int expirationTime;
        private final long timestamp;

        public ServiceDiscoveryStatistics(long totalRegistrations, long totalDeregistrations, 
                                        long totalDiscoveries, long totalHealthChecks,
                                        int registeredServices, int serviceGroups, boolean serviceDiscoveryEnabled,
                                        int registrationTimeout, int heartbeatInterval, int expirationTime, long timestamp) {
            this.totalRegistrations = totalRegistrations;
            this.totalDeregistrations = totalDeregistrations;
            this.totalDiscoveries = totalDiscoveries;
            this.totalHealthChecks = totalHealthChecks;
            this.registeredServices = registeredServices;
            this.serviceGroups = serviceGroups;
            this.serviceDiscoveryEnabled = serviceDiscoveryEnabled;
            this.registrationTimeout = registrationTimeout;
            this.heartbeatInterval = heartbeatInterval;
            this.expirationTime = expirationTime;
            this.timestamp = timestamp;
        }

        // Getter方法
        public long getTotalRegistrations() { return totalRegistrations; }
        public long getTotalDeregistrations() { return totalDeregistrations; }
        public long getTotalDiscoveries() { return totalDiscoveries; }
        public long getTotalHealthChecks() { return totalHealthChecks; }
        public int getRegisteredServices() { return registeredServices; }
        public int getServiceGroups() { return serviceGroups; }
        public boolean isServiceDiscoveryEnabled() { return serviceDiscoveryEnabled; }
        public int getRegistrationTimeout() { return registrationTimeout; }
        public int getHeartbeatInterval() { return heartbeatInterval; }
        public int getExpirationTime() { return expirationTime; }
        public long getTimestamp() { return timestamp; }
    }
}

